昨天介紹了Claim以及Identity還有Principal 等驗證中有關身分(你是誰)的物件
今天來看看驗證身分的物件
實際上在通過門禁所需要的門禁卡不是ClaimPrincipal
而是AuthencationTicket
物件
他封裝了ClaimPrincipal
以及驗證相關的上下文放在AuthenticationProperties
中
裡面包含驗證有效時間,過期時間,過期之後要重新導向的位置等資訊
還有一個能自訂所需資訊的Dictionary
AuthenticationTicket.cs
public class AuthenticationTicket
{
public string AuthenticationScheme { get; }
public ClaimsPrincipal Principal { get; }
public AuthenticationProperties Properties { get; }
}
AuthenticationScheme
指的是要如何驗證通關文件的方式,像是basic驗證,cookie驗證,jwt驗證等等
IAuthenticationHandler.cs
public interface IAuthenticationHandler
{
Task InitializeAsync(AuthenticationScheme scheme, HttpContext context);
Task<AuthenticateResult> AuthenticateAsync();
Task ChallengeAsync(AuthenticationProperties? properties);
Task ForbidAsync(AuthenticationProperties? properties);
}
AuthenticateAsync
: 定義了要如何驗證的方法,並回傳驗證結果(AuthenticateResult
)InitializeAsync
: 初始化工作,以CookieAuthenticationHandler,會對Reponse的Header添加cookieChallengeAsync
: 當使用者沒有攜帶通關文件的時候或根本不認識的門卡時,就會受到ChallengeAsync
401 unauthorized
的錯誤ForbidAsync
: 當你有帶門禁卡,櫃台小姐也認識他,但你的權限不夠時,就會被拒絕進入,403 Frobidden
的錯誤封裝了驗證結果的物件,包含有效的
AuthenticationTicket
)ClaimPrincipal
)AuthenticationProperties
)定義登出方法的介面
public interface IAuthenticationSignOutHandler : IAuthenticationHandler
{
Task SignOutAsync(AuthenticationProperties? properties);
}
定義登入方法的介面
public interface IAuthenticationSignInHandler : IAuthenticationSignOutHandler
{
Task SignInAsync(ClaimsPrincipal user, AuthenticationProperties? properties);
}
繼承自IAuthenticationSignOutHandler
我還滿喜歡這個想法的
有登入就要記得登出
處理驗證主要透過AuthenticationMiddleware
透過app.UseAuthentication()
在pipeline中加入
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
// Configure the HTTP request pipeline.
app.UseHttpsRedirection();
app.UseAuthorization();
app.UseRouting();
app.UseAuthentication();
app.MapControllers();
await app.RunAsync();
AuthenticationMiddleware.cs
public IAuthenticationSchemeProvider Schemes { get; set; }
public async Task Invoke(HttpContext context)
{
context.Features.Set<IAuthenticationFeature>(new AuthenticationFeature
{
OriginalPath = context.Request.Path,
OriginalPathBase = context.Request.PathBase
});
var handlers = context.RequestServices.GetRequiredService<IAuthenticationHandlerProvider>();
foreach (var scheme in await Schemes.GetRequestHandlerSchemesAsync())
{
var handler = await handlers.GetHandlerAsync(context, scheme.Name) as IAuthenticationRequestHandler;
if (handler != null && await handler.HandleRequestAsync())
{
return;
}
}
var defaultAuthenticate = await Schemes.GetDefaultAuthenticateSchemeAsync();
if (defaultAuthenticate != null)
{
var result = await context.AuthenticateAsync(defaultAuthenticate.Name);
if (result?.Principal != null)
{
context.User = result.Principal;
}
if (result?.Succeeded ?? false)
{
var authFeatures = new AuthenticationFeatures(result);
context.Features.Set<IHttpAuthenticationFeature>(authFeatures);
context.Features.Set<IAuthenticateResultFeature>(authFeatures);
}
}
await _next(context);
}
首先會把原始路徑設定Feature,未登入時如果被轉導到登入頁面還回的來
接著會從DI Container中取出所有的IAuthenticationHandlerProvider
然後根據所有有註冊的IAuthenticationSchemeProvider
去取有沒有符合的IAuthenticationRequestHandler
若沒有定義該物件,則會使用預設的驗證方式,在驗證通過之後,會把使用者的身分記錄在HttpContext.User
上
IAuthenticationRequestHandler.cs
public interface IAuthenticationRequestHandler : IAuthenticationHandler
{
Task<bool> HandleRequestAsync();
}
HandleRequestAsync()
方法會決定這個Request有沒有必要往後走,如果值回傳true代表請求須被中斷。